package com.dhl.fin.api.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import com.dhl.fin.api.common.dto.QueryDto;
import com.dhl.fin.api.common.service.CommonService;
import com.dhl.fin.api.common.util.CollectorUtil;
import com.dhl.fin.api.common.util.DateUtil;
import com.dhl.fin.api.common.util.MapUtil;
import com.dhl.fin.api.dao.MyStatementDao;
import com.dhl.fin.api.domain.BankAccount;
import com.dhl.fin.api.domain.FixDeposit;
import com.dhl.fin.api.dto.BankStatementRequestDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author CuiJianbo
 * @since 2025/3/16
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class FixDepositService extends CommonService<FixDeposit> {

    @Autowired
    private BankAccountService bankAccountService;

    @Autowired
    private BankStatementService bankStatementService;

    @Autowired
    private FamilyConfigService familyConfigService;

    @Autowired
    private MyStatementDao myStatementDao;


    public void addFixDepositRecord(BankStatementRequestDTO bankStatementRequestDTO) throws Exception {
        BankAccount bankAccount = new BankAccount();
        Date endDate = cn.hutool.core.date.DateUtil.offset(DateUtil.getSysDate(), DateField.YEAR, bankStatementRequestDTO.getYear());
        bankAccount.setId(bankStatementRequestDTO.getBankAccountId());
        FixDeposit fixDeposit = new FixDeposit();
        fixDeposit.setBankAccount(bankAccount);
        fixDeposit.setMoneyAmount(bankStatementRequestDTO.getIncomeMoney());
        fixDeposit.setYears(bankStatementRequestDTO.getYear());
        fixDeposit.setStartDate(DateUtil.getSysDate());
        fixDeposit.setEndDate(endDate);
        fixDeposit.setYearRate(bankStatementRequestDTO.getYearRate());
        fixDeposit.setTotalInterest(bankStatementRequestDTO.getTotalInterest());
        fixDeposit.setOperator(bankStatementRequestDTO.getOperator());
        fixDeposit.setRemark(bankStatementRequestDTO.getRemark());
        fixDeposit.setTag(bankStatementRequestDTO.getTags());
        fixDeposit.setFinished(0);

        save(fixDeposit);

    }

    public List<Map> composeDataByChild(String unicode) throws Exception {

        List<BankAccount> bankAccountList = bankAccountService.select(QueryDto.builder().available()
                .available()
                .addJoinDomain("family")
                .addJoinDomain("fixDeposits")
                .addWhere("family_unicode='" + unicode + "'")
                .addWhere("finished = 0")
                .addOrder("family.birthday")
                .build());

        List<Map> result = new LinkedList<>();
        for (BankAccount bankAccount : bankAccountList) {
            if (CollectorUtil.isNoTEmpty(bankAccount.getFixDeposits())) {
                List<FixDeposit> sortedFixDeposit = bankAccount.getFixDeposits().stream()
                        .sorted(Comparator.comparing(FixDeposit::getEndDate))
                        .collect(Collectors.toList());
                bankAccount.setFixDeposits(sortedFixDeposit);
            }
            result.add(MapUtil.builder()
                    .add("familyId", bankAccount.getFamily().getId())
                    .add("deposit", bankAccount.getFixDeposits())
                    .build());
        }

        return result;

    }

    public Map calculatePenalty(Long fixDepositId, String unicode) throws Exception {

        String penalty = familyConfigService.getPenalty(unicode);

        FixDeposit fixDeposit = get(fixDepositId);
        Double leaveMoney = fixDeposit.getMoneyAmount() * (1 - Double.valueOf(penalty) * 1.0 / 100);
        Double lostMoney = fixDeposit.getMoneyAmount() * (Double.valueOf(penalty) * 1.0 / 100);
        return MapUtil.builder()
                .add("leaveMoney", String.format("%.2f", leaveMoney))
                .add("lostMoney", String.format("%.2f", lostMoney))
                .add("rate", String.format("%s%%", penalty))
                .build();
    }

    public Double getTotalFixDepositMoney(Long bankAccountId) {
        try {
            return select(QueryDto.builder()
                    .available()
                    .addWhere("finished = 0")
                    .addWhere("bank_account.id=" + bankAccountId)
                    .build())
                    .stream()
                    .map(FixDeposit::getMoneyAmount)
                    .reduce(0.0, Double::sum);
        } catch (Exception e) {
            return 0.0;
        }
    }

    /**
     * 检查所有账户下的定期存款是否到期，到期后自动转入账户余额
     */
    public void checkFixDepositExpired() throws Exception {

        List<FixDeposit> fixDeposits = select(QueryDto.builder()
                .available()
                .addJoinDomain("bankAccount")
                .addWhere("finished = 0")
                .addWhere("bank_account.status = 'USED'")
                .addWhere("end_date < now()")
                .build());

        if (CollectorUtil.isNoTEmpty(fixDeposits)) {
            //TODO 公众号通知用户 定期存款已自动转入账户余额
            for (FixDeposit fixDeposit : fixDeposits) {

                //添加流水记录
                bankStatementService.fixDepositChangeToTimeMoney(fixDeposit);

                //更新固定存款数据为已完成
                updateFieldById(fixDeposit.getId(), "finished", 1);
            }
        }

    }


    public List<String> getFixDepositYearMonth(DateTime startTime,String familyCode){
        return myStatementDao.queryFixDepositDateTime(DateUtil.getTime(startTime),familyCode);
    }

    public List<FixDeposit> queryFixDeposit(String yearmonth, Long bankAccountId) throws Exception {
        return select(QueryDto.builder()
                .available()
                .addWhere("bank_account_id = " + bankAccountId)
                .addWhere("DATE_FORMAT(create_time, '%Y-%m') = '" + yearmonth + "'")
                .build());
    }


}
